package cn.qianxun.meta.area.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.qianxun.meta.area.dto.SysAreaCasCaderDTO;
import cn.qianxun.meta.area.dto.SysAreaDTO;
import cn.qianxun.meta.area.entity.SysArea;
import cn.qianxun.meta.area.mapper.SysAreaMapper;
import cn.qianxun.meta.area.service.ISysAreaService;
import cn.qianxun.meta.area.vo.SysAreaInsertVO;
import cn.qianxun.meta.area.vo.SysAreaQueryVO;
import cn.qianxun.meta.area.vo.SysAreaStatusVO;
import cn.qianxun.meta.area.vo.SysAreaUpdateVO;
import cn.qianxun.meta.common.core.utils.SingleFieldAssert;
import cn.qianxun.meta.common.core.utils.StringUtils;
import cn.qianxun.meta.common.core.web.vo.RemoveLongDTO;
import cn.qianxun.meta.dept.entity.SysDept;
import cn.qianxun.meta.dept.mapper.SysDeptMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.qianxun.meta.common.core.constant.Constants;
import cn.qianxun.meta.common.core.exception.ServiceException;
import cn.qianxun.meta.common.satoken.utils.LoginHelper;
import cn.qianxun.meta.redis.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 行政区域管理表 服务实现类
 * </p>
 *
 * @author fuzhilin
 * @since 2023-08-29 09:09:01
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class SysAreaServiceImpl extends ServiceImpl<SysAreaMapper, SysArea> implements ISysAreaService {

    private final SysAreaMapper sysAreaMapper;
    private final SysDeptMapper sysDeptMapper;


    /**
     * 项目启动时，初始化参数到缓存
     */
    @PostConstruct
    public void init() {
        //先清空缓存，再存入数据
        RedisUtils.deleteObject(Constants.SYS_AREA_KEY);
        //先清空缓存，再存入数据
        RedisUtils.deleteObject(Constants.SYS_AREA_MAP_KEY);
        //1.把查询的区域列表直接存入缓存
        QueryWrapper<SysArea> qw = new QueryWrapper<>();
        //查询启用的
        qw.eq("status", "1");
        qw.orderByAsc("order_num");
        List<SysArea> list = sysAreaMapper.selectList(qw);
        //2.把所有的区域按Map形式存入缓存
        Map<String, Object> map = new HashMap<>(list.size());
        for (SysArea area : list) {
            map.put(String.valueOf(area.getCode()), area.getName());
        }
        RedisUtils.setCacheMap(Constants.SYS_AREA_MAP_KEY, map);
        RedisUtils.setCacheList(Constants.SYS_AREA_KEY, list);
    }

    @Override
    public List<SysAreaDTO> getAreaList(SysAreaQueryVO vo) {
        return sysAreaMapper.getAreaList(vo);
    }

    @Override
    public void addArea(SysAreaInsertVO vo) {
        if (Constants.ZERO.equals(String.valueOf(vo.getParentId()))) {
            vo.setLevel(Constants.ONE);
        } else {
            SysArea area = sysAreaMapper.selectById(vo.getParentId());
            if (ObjectUtil.isNotNull(area)) {
                if (Constants.YES.equals(area.getLevel())) {
                    vo.setLevel(Constants.TOW);
                } else if (Constants.TOW.equals(area.getLevel())) {
                    vo.setLevel(Constants.THREE);
                }
            }
        }
        if (!Constants.AREA_LEVEL_THREE.equals(vo.getLevel())) {
            Boolean name = getIsAreaName(vo);
            if (name) {
                throw new ServiceException("该行政区域已存在！");
            }
        }
        SysArea sysArea = new SysArea();
        BeanUtil.copyProperties(vo, sysArea);
        if (null == vo.getParentId()) {
            sysArea.setParentId(0L);
            sysArea.setLevel(Constants.AREA_LEVEL_ONE);
        }
        sysArea.setCreateBy(LoginHelper.getLoginUser().getUserName());
        sysArea.setUserId(LoginHelper.getLoginUser().getUserId());
        sysArea.setCreateTime(new Date());
        clearCache();//清空缓存
        sysAreaMapper.insert(sysArea);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editArea(SysAreaUpdateVO vo) {
        SysArea sysArea = new SysArea();
        BeanUtil.copyProperties(vo, sysArea);
        SingleFieldAssert.isNull(sysArea.getCode(), "行政区域ID不能为空");
        sysArea.setUpdateBy(LoginHelper.getLoginUser().getUserName());
        sysArea.setUpdateTime(new Date());
        //清空缓存
        clearCache();
        sysAreaMapper.updateById(sysArea);
        SysAreaStatusVO statusVO = new SysAreaStatusVO();
        statusVO.setCode(vo.getCode());
        statusVO.setStatus(vo.getStatus());
        editStatus(statusVO);
    }

    @Override
    public SysAreaDTO details(Long code) {
        SingleFieldAssert.isNull(code, "行政区域ID不能为空");
        SysArea sysArea = sysAreaMapper.selectById(code);
        SysAreaDTO sysAreaDTO = new SysAreaDTO();
        BeanUtil.copyProperties(sysArea, sysAreaDTO);
        List<SysArea> list = sysAreaMapper.selectList(new LambdaQueryWrapper<>());
        if (!CollectionUtils.isEmpty(list)) {
            Long pId = sysArea.getCode();
            List<Long> pIds = new ArrayList<>();
            getParentIds(pIds, pId, list);
            sysAreaDTO.setAreaNameArray(pIds);

        }
        return sysAreaDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteAreaByIds(RemoveLongDTO vo) {
        if (CollectionUtils.isEmpty(vo.getRemoveIdList())) {
            throw new ServiceException("行政区域ID不能为空");
        }
        QueryWrapper<SysArea> qw = new QueryWrapper<>();
        qw.eq("parent_id", vo.getRemoveIdList().get(0));
        Long count = sysAreaMapper.selectCount(qw);
        if (count > 0) {
            throw new ServiceException("该行政区域下有相关的子级区域，不能删除！");
        }
        for (Long code : vo.getRemoveIdList()) {
            SysArea area = sysAreaMapper.selectById(code);

            if (Constants.AREA_STATUS_NORMAL.equals(area.getStatus())) {
                throw new ServiceException("该行政区域正在启用中，不能删除！");
            }
            boolean exitArea = isExitArea(area.getName(), area.getLevel());
            if (exitArea) {
                throw new ServiceException("该行政区域已分配，不能删除！");
            }

        }
        clearCache();//清空缓存
        sysAreaMapper.deleteBatchIds(vo.getRemoveIdList());
    }

    /**
     * 清空行政区域缓存
     */
    public void clearCache() {
        RedisUtils.deleteObject(Constants.SYS_AREA_KEY);
        RedisUtils.deleteObject(Constants.SYS_AREA_MAP_KEY);
        RedisUtils.deleteObject(Constants.SYS_AREA_MAP_OBJ_KEY);
        //1.把查询的区域列表直接存入缓存
        QueryWrapper<SysArea> qw = new QueryWrapper<>();
        //查询启用的
        qw.eq("status", "1");
        List<SysArea> list = sysAreaMapper.selectList(qw);
        RedisUtils.setCacheList(Constants.SYS_AREA_KEY, list);
        //2.把所有的区域按Map形式存入缓存
        Map<String, Object> mapObj = new HashMap<>(list.size());
        Map<String, Object> map = new HashMap<>(list.size());
        for (SysArea area : list) {
            map.put(String.valueOf(area.getCode()), area.getName());
            mapObj.put(String.valueOf(area.getCode()), area);
        }
        RedisUtils.setCacheMap(Constants.SYS_AREA_MAP_KEY, map);
        RedisUtils.setCacheObject(Constants.SYS_AREA_MAP_OBJ_KEY, mapObj);

    }

    public Boolean getIsAreaName(SysAreaInsertVO vo) {
        LambdaQueryWrapper<SysArea> wrapper = new QueryWrapper<SysArea>().lambda();
        if (0 == vo.getParentId()) {
            wrapper.eq(SysArea::getName, vo.getName());
            wrapper.eq(SysArea::getLevel, Constants.AREA_LEVEL_ONE);
            List<SysArea> list = sysAreaMapper.selectList(wrapper);
            return list.size() > 0 ? true : false;
        } else {
            wrapper.eq(SysArea::getName, vo.getName());
            wrapper.eq(SysArea::getLevel, vo.getLevel());
            List<SysArea> list = sysAreaMapper.selectList(wrapper);
            return list.size() > 0 ? true : false;
        }

    }

    /**
     * 变更区域状态
     *
     * @param vo
     */
    @Override
    public void editStatus(SysAreaStatusVO vo) {
        SysArea sysArea = sysAreaMapper.selectById(vo.getCode());
        if (ObjectUtil.isNull(sysArea)) {
            throw new ServiceException("抱歉,您所查的区域不存在！");
        }
        List<SysArea> list = sysAreaMapper.selectList(new QueryWrapper<SysArea>().lambda());
        List<Long> childIds = new ArrayList<>();
        childIds.add(sysArea.getCode());
        getChildPerms(list, childIds, sysArea.getCode());
        sysAreaMapper.updateByIds(vo.getStatus(), childIds);
        clearCache();
    }

    @Override
    public List<SysAreaDTO> queryProvinceCityTwoList() {
        LambdaQueryWrapper<SysArea> lqw = new LambdaQueryWrapper<SysArea>();
        lqw.ne(SysArea::getLevel, "3");
        List<SysArea> provinceCityList = sysAreaMapper.selectList(lqw);
        List<SysAreaDTO> sysAreaDTOList =
                provinceCityList.stream().map(sysArea -> {
                    SysAreaDTO sysAreaDto = new SysAreaDTO();
                    BeanUtil.copyProperties(sysArea, sysAreaDto);
                    return sysAreaDto;
                }).collect(Collectors.toList());
        return sysAreaDTOList;
    }

    @Override
    public List<SysAreaCasCaderDTO> getAreaListCasCaderData() {
        //先从缓存中获取，若不存在，再进行查询
        List<SysArea> areaList = RedisUtils.getCacheList(Constants.SYS_AREA_KEY);
        if (areaList == null || areaList.size() == 0) {
            areaList = sysAreaMapper.selectList(new LambdaQueryWrapper<SysArea>()
                    .eq(SysArea::getStatus, Constants.YES)
                    .orderByAsc(SysArea::getOrderNum));
        }
        List<SysAreaCasCaderDTO> sysAreaDTOList =
                areaList.stream().map(sysArea -> {
                    SysAreaCasCaderDTO sysAreaDto = new SysAreaCasCaderDTO();
                    sysAreaDto.setValue(sysArea.getCode());
                    sysAreaDto.setLabel(sysArea.getName());
                    sysAreaDto.setParentId(sysArea.getParentId());
                    return sysAreaDto;
                }).collect(Collectors.toList());
        return sysAreaDTOList;
    }


    @Override
    public Long getLastCode(String provinceName, String cityName, String areaName) {
        Long code = null;
        //查询省市区code
        List<SysAreaCasCaderDTO> areaDTOs = getAreaListCasCaderData();
        if (CollectionUtil.isNotEmpty(areaDTOs)) {
            LambdaQueryWrapper<SysArea> qw = new LambdaQueryWrapper<SysArea>();
            //省，只要最下级code
            qw.eq(SysArea::getName, provinceName);
            SysArea province = sysAreaMapper.selectOne(qw);
            code = province == null ? null : province.getCode();
            if (province != null && StringUtils.isNotEmpty(cityName)) {
                //市
                qw.clear();
                qw.eq(SysArea::getName, cityName);
                qw.eq(SysArea::getParentId, province.getCode());
                SysArea city = sysAreaMapper.selectOne(qw);
                code = city == null ? province.getCode() : city.getCode();
                if (city != null && StringUtils.isNotEmpty(areaName)) {
                    //区
                    qw.clear();
                    qw.eq(SysArea::getName, areaName);
                    qw.eq(SysArea::getParentId, city.getCode());
                    SysArea area = sysAreaMapper.selectOne(qw);
                    code = area == null ? city.getCode() : area.getCode();
                }
            }
        }
        return code;
    }


    /**
     * 根据parentId递归子级
     */
    public void getChildPerms(List<SysArea> list, List<Long> finalList, Long parentId) {

        for (Iterator<SysArea> iterator = list.iterator(); iterator.hasNext(); ) {
            SysArea t = (SysArea) iterator.next();
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (parentId.equals(t.getParentId())) {
                getChildPerms(list, finalList, t.getCode());
                finalList.add(t.getCode());
            }
        }
    }

    /**
     * 根据子节点遍历出所有父节点
     *
     * @param pIds
     * @param pId
     * @param allList
     */
    public void getParentIds(List<Long> pIds, Long pId, List<SysArea> allList) {
        for (SysArea area : allList) {
            if (area.getCode().equals(pId)) {
                if (area.getParentId() != null) {
                    getParentIds(pIds, area.getParentId(), allList);
                }
                pIds.add(area.getCode());
                break;
            }
        }
    }


    /**
     * 判断是否分配
     *
     * @param name
     * @param type
     * @return
     */
    public boolean isExitArea(String name, String type) {
        LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
        if (Constants.AREA_LEVEL_ONE.equals(type)) {
            wrapper.eq(SysDept::getProvinceName, name);
        }
        if (Constants.AREA_LEVEL_TWO.equals(type)) {
            wrapper.eq(SysDept::getCityName, name);
        }
        if (Constants.AREA_LEVEL_THREE.equals(type)) {
            wrapper.eq(SysDept::getAreaName, name);
        }
        Long count = sysDeptMapper.selectCount(wrapper);
        return count > 0 ? true : false;
    }

}
